package org.iogame.util;

import cn.hutool.core.util.ClassUtil;
import cn.hutool.core.util.ReflectUtil;
import com.iohao.game.action.skeleton.annotation.ActionController;
import com.iohao.game.action.skeleton.annotation.ActionMethod;
import com.iohao.game.action.skeleton.core.CmdKit;
import lombok.extern.slf4j.Slf4j;
import org.iogame.annotation.Desc;
import org.iogame.data.DataMap;
import org.iogame.dto.ClassInfo;
import org.iogame.dto.MethodInfo;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.*;


/**
 * @author lc
 * @since 2022/10/1
 */
@Slf4j
public final class ClsUtil {


    /**
     * 获取方法参数
     *
     * @since 2022/10/1
     */
    private static List<String> getMethodParam(Parameter p) {
        ArrayList<String> fieldList = new ArrayList<>();
        Field[] fields = cn.hutool.core.util.ClassUtil.getDeclaredFields(p.getType());
        for (Field field : fields) {
            fieldList.add(field.getName());
        }
        return fieldList;
    }

    /**
     * 扫描包
     *
     * @since 2022/10/1
     */
    public static void scanPackage(Class<?> cls) {
        String packageName = ClassUtil.getPackage(cls);
        Set<Class<?>> classSet = ClassUtil.scanPackage(packageName);
        // 获取所有类
        HashSet<Class<?>> actionSet = new HashSet<>();
        for (Class<?> v : classSet) {
            if (v.isAnnotationPresent(ActionController.class)) {
                actionSet.add(v);
            }
        }
        // 获取所有方法
        for (Class<?> v : actionSet) {
            ActionController actionController = v.getAnnotation(ActionController.class);
            String[] split = v.getName().split("\\.");
            String className = split[split.length - 1] + "_";
            Method[] methods = ReflectUtil.getMethods(v);

            // 类信息
            ClassInfo info = new ClassInfo();
            info.setClassName(className);
            Desc desc = v.getAnnotation(Desc.class);
            if (desc != null) {
                info.setDesc(desc.value());
                info.setLongDesc(desc.longDesc());
            }
            DataMap.CLASS_INFO_LIST.add(info);


            ArrayList<MethodInfo> scanMethods = scanMethods(methods, actionController.value(), className);
            DataMap.MAP.put(className, scanMethods);
        }
    }


    public static ArrayList<MethodInfo> scanMethods(Method[] methods, int cmd, String className){
        ArrayList<MethodInfo> list = new ArrayList<>();
        for (Method method : methods) {
            ActionMethod actionMethod = method.getAnnotation(ActionMethod.class);
            if (actionMethod != null) {
                MethodInfo m = new MethodInfo();
                m.setMethodName(method.getName());
                m.setDesc(getMethodDesc(method));
                m.setLongDesc(getMethodLongDesc(method));

                Parameter[] parameters = method.getParameters();
                // 暂时不做多参数判断
                if (parameters.length > 2) {
                    continue;
                }
                int merge = CmdKit.merge(cmd, actionMethod.value());
                String key = className + method.getName();
                for (Parameter p : parameters) {
                    if (TypeUtil.skipType(p)) {
                        continue;
                    }
                    HashMap<String, Object> t = new HashMap<>();
                    List<String> param = ClsUtil.getMethodParam(p);
                    param.forEach((e) -> {
                        t.put(e, null);
                    });
                    m.setMethodParam(t);
                    // 类名+方法名，定位需要反射的cls
                    try {
                        Object o = p.getType().getDeclaredConstructor().newInstance();
                        DataMap.PARAM_MAP.put(key, o);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
                // 保存返回结果
                DataMap.ROUTER_CLS_MAP.put(merge, method.getReturnType());
                DataMap.ROUTER_MAP.put(key, merge);
                list.add(m);
            }
        }
        return list;
    }

    // 获取短描述
    public static String getMethodDesc(Method method){
        Desc desc = method.getAnnotation(Desc.class);
        return desc == null ? "" : desc.value();
    }
    // 获取长描述
    public static String getMethodLongDesc(Method method){
        Desc desc = method.getAnnotation(Desc.class);
        return desc == null ? "" : desc.longDesc();
    }

}
